//http://www.mathematik.uni-dortmund.de/~goeddeke/gpgpu/testati.cpp

// bibliotecas do C
#include <stdio.h>
#include <stdlib.h>
// Bibliotecas do glew e do glut
#include "C:\Users\max\Desktop\opengl GLSL\helloGPGPU_GLSL-1.0.2\helloGPGPU_GLSL-1.0.2\glew-1.9.0-win32\glew-1.9.0\include\GL/glew.h"
#include "C:\Users\max\Desktop\opengl GLSL\freeglut-2.8.0\freeglut-2.8.0\include\GL/glut.h"

static int texSize = 4;
static GLenum textarget = GL_TEXTURE_2D;
static GLenum texinternalformat = GL_RGBA_FLOAT32_ATI;


int main(int argc, char **argv) {
    //declara o tamanho da textura , os dados serão um vetor  
    // de tamanho texSize*TexSize*4 
    // cria os dados teste e os preenche sem muitos critérios 
    float* data = (float*)malloc(4*texSize*texSize*sizeof(float));
    float* result = (float*)malloc(4*texSize*texSize*sizeof(float));
    for (int i=0; i<texSize*texSize*4; i++)
        data[i] = i+1.0;

	// Inicia o freeglut para pegar um contexto
	// GL e repassar para a janela criada 
	// os argumentos do programa original 
    glutInit (&argc, argv);// cria a janela com o GLUT e passa os argumentos do programa original para esta janela 
    glutCreateWindow("TEST1");
    glewInit();

	// mapeamento entre as coordenadas geometricas e as coordenadas das texturas pixel=elemento de textura=mapeamento dos dados 
	// signigica que somos capazes de transformar um indice do dado alocado na CPU para a coordenada do dado alocado na GPU
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,texSize,0.0,texSize);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0,0,texSize,texSize);

	// Permite criar um buffer fora da janela e utiliza-o para que ele seja o portador das operacoes de calculo 
    GLuint fb;
    glGenFramebuffersEXT(1,&fb); 
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);
    
	// cria a textura 
    GLuint tex;
    glGenTextures (1, &tex);
    glBindTexture(textarget,tex);
    // define os parametros da textura
    glTexParameteri(textarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(textarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(textarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(textarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
    // define que a testura terá formato de ponto flutuante 
    glTexImage2D(textarget,0,texinternalformat,texSize,texSize,0,GL_RGBA,GL_FLOAT,0);
    // Insere a textura no FBO que permite o acesso sem ter que reformatar os dados à estrutura da GPU 
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget,tex,0);
    
	// redireciona o ponteiro para o endereco de memoria a ser escrito
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
	//Define o ponto inical como a coordenada de referencia
	glRasterPos2i(0,0);
	//Transfere o vetor data para a textura 
	glDrawPixels(texSize,texSize,GL_RGBA,GL_FLOAT,data);
    // redireciona o ponteiro para o endereco de memoria a ser lido
    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
	// Le a memória a partir do começo (coordenada 0,0) 
    glReadPixels(0, 0, texSize, texSize,GL_RGBA,GL_FLOAT,result);
    // print out results
    printf("Data before roundtrip:\n");
    for (int i=0; i<texSize*texSize*4; i++)
        printf("%f\n",data[i]);
    printf("Data after roundtrip:\n");
    for (int i=0; i<texSize*texSize*4; i++)
        printf("%f\n",result[i]);
    // clean up
    free(data);
    free(result);
    glDeleteFramebuffersEXT (1,&fb);
    glDeleteTextures (1,&tex);
    return 0;
}
